package com.wuliu.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author realue
 * @version 1.0
 * @date 2022-10-12 17:35
 */
public final class ThreadLocalContext {

    public static final String CURRENT_SYSUSER_VO_KEY = ThreadLocalContext.class.getName() + "_CURRENT_SYSUSER_VO_KEY";

    public static final String CURRENT_TOKEN_KEY = ThreadLocalContext.class.getName() + "_CURRENT_TOKEN_KEY";

    private static final Logger logger = LoggerFactory.getLogger(ThreadLocalContext.class);

    private static final ThreadLocal<Map<Object, Object>> threadLocal = new InheritableThreadLocal<>();

    private ThreadLocalContext() {
    }

    public static Map<Object, Object> getThreadLocal() {
        if (threadLocal.get() == null) {
            return Collections.emptyMap();
        } else {
            return new HashMap<Object, Object>(threadLocal.get());
        }
    }

    public static void setThreadLocal(Map<Object, Object> newResources) {
        if (CollectionUtils.isEmpty(newResources)) {
            return;
        }
        ensureResourcesInitialized();
        threadLocal.get().clear();
        threadLocal.get().putAll(newResources);
    }

    private static void ensureResourcesInitialized() {
        if (threadLocal.get() == null) {
            threadLocal.set(new HashMap<Object, Object>());
        }
    }

    public static Object get(Object key) {
        if (logger.isTraceEnabled()) {
            String msg = "get() - in thread [" + Thread.currentThread().getName() + "]";
            logger.trace(msg);
        }

        Object value = getValue(key);
        if ((value != null) && logger.isTraceEnabled()) {
            String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]";
            logger.trace(msg);
        }
        return value;
    }

    public static void put(Object key, Object value) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }

        if (value == null) {
            remove(key);
            return;
        }

        ensureResourcesInitialized();
        threadLocal.get().put(key, value);

        if (logger.isTraceEnabled()) {
            String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + key + "] to thread " + "[" + Thread.currentThread().getName() + "]";
            logger.trace(msg);
        }
    }

    public static Object remove(Object key) {
        Map<Object, Object> perThreadResources = threadLocal.get();
        Object value = perThreadResources != null ? perThreadResources.remove(key) : null;

        if ((value != null) && logger.isTraceEnabled()) {
            String msg = "Removed value of type [" + value.getClass().getName() + "] for key [" + key + "]" + "from thread [" + Thread.currentThread().getName() + "]";
            logger.trace(msg);
        }

        return value;
    }

    private static Object getValue(Object key) {
        Map<Object, Object> perThreadResources = threadLocal.get();
        return perThreadResources != null ? perThreadResources.get(key) : null;
    }

    public static void bindSysUser(Object sysUser) {
        if (sysUser != null) {
            put(CURRENT_SYSUSER_VO_KEY, sysUser);
        }
    }

    public static void unBindSysUser() {
        remove(CURRENT_SYSUSER_VO_KEY);
    }

    public static Object getCurrentSysUser() {
        return get(CURRENT_SYSUSER_VO_KEY);
    }

    public static void bindToken(Object token) {
        if (token != null) {
            put(CURRENT_TOKEN_KEY, token);
        }
    }

    public static void unBindToken() {
        remove(CURRENT_TOKEN_KEY);
    }

    public static Object getCurrentToken() {
        return get(CURRENT_TOKEN_KEY);
    }
}
